﻿using LibBinary.DataSource;
using LibBinary.FileData;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace LibBinary.FileDeclaration.Binary
{
    public class ObjectDeclaration : IFileDeclaration
    {
        private readonly IObjectDeclarationProvider provider;
        private readonly int strlen;

        public ObjectDeclaration(IObjectDeclarationProvider provider, int strlen = 0)
        {
            this.provider = provider;
            this.strlen = strlen;
        }

        private string ReadString(BinaryFileSource src)
        {
            var len = strlen == 0 ? src.Read<byte>() : strlen;

            byte[] buffer = new byte[len];
            for (int i = 0; i < len; ++i)
            {
                buffer[i] = src.Read<byte>();
            }
            return Encoding.ASCII.GetString(buffer);
        }

        private void WriteString(BinaryFileSource src, string id)
        {
            byte[] buffer = Encoding.ASCII.GetBytes(id);
            if (strlen != 0)
            {
                if (buffer.Length != strlen)
                {
                    throw new WritingFormatException("Object id length mismatch.");
                }
            }
            else
            {
                src.Write<byte>((byte)buffer.Length);
            }
            foreach (byte b in buffer)
            {
                src.Write<byte>(b);
            }
        }

        public AbstractFileData Read(BinaryFileSource src, AbstractFileData parentNode)
        {
            string object_id = ReadString(src);
            var ret = new ObjectData(parentNode);
            ret.ObjectID = object_id;
            ret.Data = provider.Get(object_id).Read(src, ret).As<StructuredData>();
            return ret;
        }

        public void Write(BinaryFileSource src, AbstractFileData data)
        {
            var cdata = data.As<ObjectData>();
            string object_id = cdata.ObjectID;
            WriteString(src, object_id);
            provider.Get(object_id).Write(src, cdata.Data);
        }
    }
}
